/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2025 DBeaver Corp and others
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jkiss.util;

import org.jkiss.code.NotNull;
import org.jkiss.utils.AlphanumericComparator;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class AlphanumericComparatorTest {
    private final AlphanumericComparator comparator = AlphanumericComparator.getInstance();

    @Test
    public void testAlphanumericComparator() {
        assertComparatorLowercaseCasesPass(comparator);
    }

    @Test
    public void testAlphanumericComparatorIgnoreCaseTestInsensitive() {
        assertComparatorLowercaseCasesPass(comparator::compareIgnoreCase);
    }

    @Test
    public void comparatorIgnoreCaseTestBorderCases() {
        AlphanumericComparator alphanumericComparator = AlphanumericComparator.getInstance();
        // even cases letters
        assertEquals(0, alphanumericComparator.compareIgnoreCase("A", "A"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("a", "A"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("a", "a"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("test", "TEST"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("TesT", "TEst"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("TesT", "TEst"));
        assertEquals(0, alphanumericComparator.compareIgnoreCase("LongStringWithCASE", "longstringwithcase"));

        // not even
        assertTrue(alphanumericComparator.compareIgnoreCase("b", "a") > 0);
        assertTrue(alphanumericComparator.compareIgnoreCase("b", "A") > 0);
        assertTrue(alphanumericComparator.compareIgnoreCase("a2", "A1") > 0);
        assertTrue(alphanumericComparator.compareIgnoreCase("aa", "a") > 0);
    }

    @Test
    public void comparatorContractTest() {
        var input = List.of(
            "tb_2024062717021917181100_a",
            "tb_2024062717021917181100_b",
            "tb_2024062717021917181100_c",
            "tb_2024062717021987321300_a",
            "tb_2024062717021987321300_b",
            "tb_2024062717021987321300_c",
            "tb_2024062717025873983900_a",
            "tb_2024062717025873983900_b",
            "tb_2024062717025873983900_c",
            "tb_2024062717025946972500_a",
            "tb_2024062717025946972500_b",
            "tb_2024062717025946972500_c",
            "tb_2024062808443487429400_a",
            "tb_2024062808443487429400_b",
            "tb_2024062808443487429400_c",
            "tb_2024062808443565182500_a",
            "tb_2024062808443565182500_b",
            "tb_2024062808443565182500_c",
            "tb_2024062808485852240700_a",
            "tb_2024062808485852240700_b",
            "tb_2024062808485852240700_c",
            "tb_2024062808485922846100_a",
            "tb_2024062808485922846100_b",
            "tb_2024062808485922846100_c",
            "tb_2024062808510343420400_a",
            "tb_2024062808510343420400_b",
            "tb_2024062808510343420400_c",
            "tb_2024062808510415832700_a",
            "tb_2024062808510415832700_b",
            "tb_2024062808510415832700_c",
            "tb_2024062808555338721800_a",
            "tb_2024062808555338721800_b",
            "tb_2024062808555338721800_c",
            "tb_2024062808555413504500_a",
            "tb_2024062808555413504500_b",
            "tb_2024062808555413504500_c",
            "tb_2024062809004817546200_a",
            "tb_2024062809004817546200_b",
            "tb_2024062809004817546200_c",
            "tb_2024062809004891493500_a",
            "tb_2024062809004891493500_b",
            "tb_2024062809004891493500_c",
            "tb_2024062809072784889600_a",
            "tb_2024062809072784889600_b",
            "tb_2024062809072784889600_c",
            "tb_2024062809072838776600_a",
            "tb_2024062809072838776600_b",
            "tb_2024062809072838776600_c",
            "tb_2024062809072959260600_a",
            "tb_2024062809072959260600_b",
            "tb_2024062809072959260600_c",
            "tb_2024062809110749009200_a",
            "tb_2024062809110749009200_b",
            "tb_2024062809110749009200_c",
            "tb_2024062809110795555700_a",
            "tb_2024062809110795555700_b",
            "tb_2024062809110795555700_c",
            "tb_2024062809110913591500_a",
            "tb_2024062809110913591500_b",
            "tb_2024062809110913591500_c",
            "tb_2024062809172348494500_a",
            "tb_2024062809172348494500_b",
            "tb_2024062809172348494500_c",
            "tb_2024062809172394170600_a",
            "tb_2024062809172394170600_b",
            "tb_2024062809172394170600_c",
            "tb_2024062809172530677400_a",
            "tb_2024062809172530677400_b",
            "tb_2024062809172530677400_c",
            "tb_2024062809260991490600_a",
            "tb_2024062809260991490600_b",
            "tb_2024062809260991490600_c",
            "tb_202406280926103824900_a",
            "tb_202406280926103824900_b",
            "tb_202406280926103824900_c",
            "tb_2024062809261166102200_a",
            "tb_2024062809261166102200_b",
            "tb_2024062809261166102200_c",
            "tb_2024062809271296363100_a",
            "tb_2024062809271296363100_b",
            "tb_2024062809271296363100_c",
            "tb_2024062809271342741900_a",
            "tb_2024062809271342741900_b",
            "tb_2024062809271342741900_c",
            "tb_2024062809271471046200_a",
            "tb_2024062809271471046200_b",
            "tb_2024062809271471046200_c",
            "tb_2024062809504349285400_a",
            "tb_2024062809504349285400_b",
            "tb_2024062809504349285400_c",
            "tb_2024062809504414294300_a",
            "tb_2024062809504414294300_b",
            "tb_2024062809504414294300_c",
            "tb_2024062809504557202400_a",
            "tb_2024062809504557202400_b",
            "tb_2024062809504557202400_c",
            "tb_2024062809552812364500_a",
            "tb_2024062809552812364500_b",
            "tb_2024062809552812364500_c"
        );

        var expected = List.of(
            "tb_202406280926103824900_a",
            "tb_202406280926103824900_b",
            "tb_202406280926103824900_c",
            "tb_2024062717021917181100_a",
            "tb_2024062717021917181100_b",
            "tb_2024062717021917181100_c",
            "tb_2024062717021987321300_a",
            "tb_2024062717021987321300_b",
            "tb_2024062717021987321300_c",
            "tb_2024062717025873983900_a",
            "tb_2024062717025873983900_b",
            "tb_2024062717025873983900_c",
            "tb_2024062717025946972500_a",
            "tb_2024062717025946972500_b",
            "tb_2024062717025946972500_c",
            "tb_2024062808443487429400_a",
            "tb_2024062808443487429400_b",
            "tb_2024062808443487429400_c",
            "tb_2024062808443565182500_a",
            "tb_2024062808443565182500_b",
            "tb_2024062808443565182500_c",
            "tb_2024062808485852240700_a",
            "tb_2024062808485852240700_b",
            "tb_2024062808485852240700_c",
            "tb_2024062808485922846100_a",
            "tb_2024062808485922846100_b",
            "tb_2024062808485922846100_c",
            "tb_2024062808510343420400_a",
            "tb_2024062808510343420400_b",
            "tb_2024062808510343420400_c",
            "tb_2024062808510415832700_a",
            "tb_2024062808510415832700_b",
            "tb_2024062808510415832700_c",
            "tb_2024062808555338721800_a",
            "tb_2024062808555338721800_b",
            "tb_2024062808555338721800_c",
            "tb_2024062808555413504500_a",
            "tb_2024062808555413504500_b",
            "tb_2024062808555413504500_c",
            "tb_2024062809004817546200_a",
            "tb_2024062809004817546200_b",
            "tb_2024062809004817546200_c",
            "tb_2024062809004891493500_a",
            "tb_2024062809004891493500_b",
            "tb_2024062809004891493500_c",
            "tb_2024062809072784889600_a",
            "tb_2024062809072784889600_b",
            "tb_2024062809072784889600_c",
            "tb_2024062809072838776600_a",
            "tb_2024062809072838776600_b",
            "tb_2024062809072838776600_c",
            "tb_2024062809072959260600_a",
            "tb_2024062809072959260600_b",
            "tb_2024062809072959260600_c",
            "tb_2024062809110749009200_a",
            "tb_2024062809110749009200_b",
            "tb_2024062809110749009200_c",
            "tb_2024062809110795555700_a",
            "tb_2024062809110795555700_b",
            "tb_2024062809110795555700_c",
            "tb_2024062809110913591500_a",
            "tb_2024062809110913591500_b",
            "tb_2024062809110913591500_c",
            "tb_2024062809172348494500_a",
            "tb_2024062809172348494500_b",
            "tb_2024062809172348494500_c",
            "tb_2024062809172394170600_a",
            "tb_2024062809172394170600_b",
            "tb_2024062809172394170600_c",
            "tb_2024062809172530677400_a",
            "tb_2024062809172530677400_b",
            "tb_2024062809172530677400_c",
            "tb_2024062809260991490600_a",
            "tb_2024062809260991490600_b",
            "tb_2024062809260991490600_c",
            "tb_2024062809261166102200_a",
            "tb_2024062809261166102200_b",
            "tb_2024062809261166102200_c",
            "tb_2024062809271296363100_a",
            "tb_2024062809271296363100_b",
            "tb_2024062809271296363100_c",
            "tb_2024062809271342741900_a",
            "tb_2024062809271342741900_b",
            "tb_2024062809271342741900_c",
            "tb_2024062809271471046200_a",
            "tb_2024062809271471046200_b",
            "tb_2024062809271471046200_c",
            "tb_2024062809504349285400_a",
            "tb_2024062809504349285400_b",
            "tb_2024062809504349285400_c",
            "tb_2024062809504414294300_a",
            "tb_2024062809504414294300_b",
            "tb_2024062809504414294300_c",
            "tb_2024062809504557202400_a",
            "tb_2024062809504557202400_b",
            "tb_2024062809504557202400_c",
            "tb_2024062809552812364500_a",
            "tb_2024062809552812364500_b",
            "tb_2024062809552812364500_c"
        );

        assertComparatorSortingMatches(input, expected, comparator);
    }

    @Test
    public void comparatorIgnoreCaseContractTest() {
        var input = List.of(
            "tb_2024062717021917181100_a",
            "tb_2024062717021917181100_b",
            "tb_2024062717021917181100_c",
            "tb_2024062717021987321300_a",
            "tb_2024062717021987321300_b",
            "tb_2024062717021987321300_c",
            "tb_2024062717025873983900_a",
            "tb_2024062717025873983900_b",
            "tb_2024062717025873983900_c",
            "tb_2024062717025946972500_a",
            "tb_2024062717025946972500_b",
            "tb_2024062717025946972500_c",
            "tb_2024062808443487429400_a",
            "tb_2024062808443487429400_b",
            "tb_2024062808443487429400_c",
            "tb_2024062808443565182500_a",
            "tb_2024062808443565182500_b",
            "tb_2024062808443565182500_c",
            "tb_2024062808485852240700_a",
            "tb_2024062808485852240700_b",
            "tb_2024062808485852240700_c",
            "tb_2024062808485922846100_a",
            "tb_2024062808485922846100_b",
            "tb_2024062808485922846100_c",
            "tb_2024062808510343420400_a",
            "tb_2024062808510343420400_b",
            "tb_2024062808510343420400_c",
            "tb_2024062808510415832700_a",
            "tb_2024062808510415832700_b",
            "tb_2024062808510415832700_c",
            "tb_2024062808555338721800_a",
            "tb_2024062808555338721800_b",
            "tb_2024062808555338721800_c",
            "tb_2024062808555413504500_a",
            "tb_2024062808555413504500_b",
            "tb_2024062808555413504500_c",
            "tb_2024062809004817546200_a",
            "tb_2024062809004817546200_b",
            "tb_2024062809004817546200_c",
            "tb_2024062809004891493500_a",
            "tb_2024062809004891493500_b",
            "tb_2024062809004891493500_c",
            "tb_2024062809072784889600_a",
            "tb_2024062809072784889600_b",
            "tb_2024062809072784889600_c",
            "tb_2024062809072838776600_a",
            "tb_2024062809072838776600_b",
            "tb_2024062809072838776600_c",
            "tb_2024062809072959260600_a",
            "tb_2024062809072959260600_b",
            "tb_2024062809072959260600_c",
            "tb_2024062809110749009200_a",
            "tb_2024062809110749009200_b",
            "tb_2024062809110749009200_c",
            "tb_2024062809110795555700_a",
            "tb_2024062809110795555700_b",
            "tb_2024062809110795555700_c",
            "tb_2024062809110913591500_a",
            "tb_2024062809110913591500_b",
            "tb_2024062809110913591500_c",
            "tb_2024062809172348494500_a",
            "tb_2024062809172348494500_b",
            "tb_2024062809172348494500_c",
            "tb_2024062809172394170600_a",
            "tb_2024062809172394170600_b",
            "tb_2024062809172394170600_c",
            "tb_2024062809172530677400_a",
            "tb_2024062809172530677400_b",
            "tb_2024062809172530677400_c",
            "tb_2024062809260991490600_a",
            "tb_2024062809260991490600_b",
            "tb_2024062809260991490600_c",
            "tb_202406280926103824900_a",
            "tb_202406280926103824900_b",
            "tb_202406280926103824900_c",
            "tb_2024062809261166102200_a",
            "tb_2024062809261166102200_b",
            "tb_2024062809261166102200_c",
            "tb_2024062809271296363100_a",
            "tb_2024062809271296363100_b",
            "tb_2024062809271296363100_c",
            "tb_2024062809271342741900_a",
            "tb_2024062809271342741900_b",
            "tb_2024062809271342741900_c",
            "tb_2024062809271471046200_a",
            "tb_2024062809271471046200_b",
            "tb_2024062809271471046200_c",
            "tb_2024062809504349285400_a",
            "tb_2024062809504349285400_b",
            "tb_2024062809504349285400_c",
            "tb_2024062809504414294300_a",
            "tb_2024062809504414294300_b",
            "tb_2024062809504414294300_c",
            "tb_2024062809504557202400_a",
            "tb_2024062809504557202400_b",
            "tb_2024062809504557202400_c",
            "tb_2024062809552812364500_a",
            "tb_2024062809552812364500_b",
            "tb_2024062809552812364500_c"
        );

        var expected = List.of(
            "tb_202406280926103824900_a",
            "tb_202406280926103824900_b",
            "tb_202406280926103824900_c",
            "tb_2024062717021917181100_a",
            "tb_2024062717021917181100_b",
            "tb_2024062717021917181100_c",
            "tb_2024062717021987321300_a",
            "tb_2024062717021987321300_b",
            "tb_2024062717021987321300_c",
            "tb_2024062717025873983900_a",
            "tb_2024062717025873983900_b",
            "tb_2024062717025873983900_c",
            "tb_2024062717025946972500_a",
            "tb_2024062717025946972500_b",
            "tb_2024062717025946972500_c",
            "tb_2024062808443487429400_a",
            "tb_2024062808443487429400_b",
            "tb_2024062808443487429400_c",
            "tb_2024062808443565182500_a",
            "tb_2024062808443565182500_b",
            "tb_2024062808443565182500_c",
            "tb_2024062808485852240700_a",
            "tb_2024062808485852240700_b",
            "tb_2024062808485852240700_c",
            "tb_2024062808485922846100_a",
            "tb_2024062808485922846100_b",
            "tb_2024062808485922846100_c",
            "tb_2024062808510343420400_a",
            "tb_2024062808510343420400_b",
            "tb_2024062808510343420400_c",
            "tb_2024062808510415832700_a",
            "tb_2024062808510415832700_b",
            "tb_2024062808510415832700_c",
            "tb_2024062808555338721800_a",
            "tb_2024062808555338721800_b",
            "tb_2024062808555338721800_c",
            "tb_2024062808555413504500_a",
            "tb_2024062808555413504500_b",
            "tb_2024062808555413504500_c",
            "tb_2024062809004817546200_a",
            "tb_2024062809004817546200_b",
            "tb_2024062809004817546200_c",
            "tb_2024062809004891493500_a",
            "tb_2024062809004891493500_b",
            "tb_2024062809004891493500_c",
            "tb_2024062809072784889600_a",
            "tb_2024062809072784889600_b",
            "tb_2024062809072784889600_c",
            "tb_2024062809072838776600_a",
            "tb_2024062809072838776600_b",
            "tb_2024062809072838776600_c",
            "tb_2024062809072959260600_a",
            "tb_2024062809072959260600_b",
            "tb_2024062809072959260600_c",
            "tb_2024062809110749009200_a",
            "tb_2024062809110749009200_b",
            "tb_2024062809110749009200_c",
            "tb_2024062809110795555700_a",
            "tb_2024062809110795555700_b",
            "tb_2024062809110795555700_c",
            "tb_2024062809110913591500_a",
            "tb_2024062809110913591500_b",
            "tb_2024062809110913591500_c",
            "tb_2024062809172348494500_a",
            "tb_2024062809172348494500_b",
            "tb_2024062809172348494500_c",
            "tb_2024062809172394170600_a",
            "tb_2024062809172394170600_b",
            "tb_2024062809172394170600_c",
            "tb_2024062809172530677400_a",
            "tb_2024062809172530677400_b",
            "tb_2024062809172530677400_c",
            "tb_2024062809260991490600_a",
            "tb_2024062809260991490600_b",
            "tb_2024062809260991490600_c",
            "tb_2024062809261166102200_a",
            "tb_2024062809261166102200_b",
            "tb_2024062809261166102200_c",
            "tb_2024062809271296363100_a",
            "tb_2024062809271296363100_b",
            "tb_2024062809271296363100_c",
            "tb_2024062809271342741900_a",
            "tb_2024062809271342741900_b",
            "tb_2024062809271342741900_c",
            "tb_2024062809271471046200_a",
            "tb_2024062809271471046200_b",
            "tb_2024062809271471046200_c",
            "tb_2024062809504349285400_a",
            "tb_2024062809504349285400_b",
            "tb_2024062809504349285400_c",
            "tb_2024062809504414294300_a",
            "tb_2024062809504414294300_b",
            "tb_2024062809504414294300_c",
            "tb_2024062809504557202400_a",
            "tb_2024062809504557202400_b",
            "tb_2024062809504557202400_c",
            "tb_2024062809552812364500_a",
            "tb_2024062809552812364500_b",
            "tb_2024062809552812364500_c"
        );

        assertComparatorSortingMatches(input, expected, comparator::compareIgnoreCase);
    }

    private void assertComparatorLowercaseCasesPass(@NotNull Comparator<? super CharSequence> comparator) {
        assertComparatorSortingMatches(
            List.of("img12", "img10", "img2", "img1", "img100_1", "img100_11", "img100", "img100_10", "img100_5"),
            List.of("img1", "img2", "img10", "img12", "img100", "img100_1", "img100_5", "img100_10", "img100_11"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("file1000", "file100", "file10", "file2", "file1", "file11", "file200", "file20", "file2a", "file2b"),
            List.of("file1", "file2", "file2a", "file2b", "file10", "file11", "file20", "file100", "file200", "file1000"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("doc10", "doc2", "doc20", "doc1", "doc3", "doc15", "doc4"),
            List.of("doc1", "doc2", "doc3", "doc4", "doc10", "doc15", "doc20"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("page2", "page12", "page3", "page22", "page4", "page13", "page23"),
            List.of("page2", "page3", "page4", "page12", "page13", "page22", "page23"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("item-5", "item-1", "item-10", "item-2", "item-11", "item-3", "item-20", "item-15"),
            List.of("item-1", "item-2", "item-3", "item-5", "item-10", "item-11", "item-15", "item-20"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("abc123def45", "abc12def345", "abc1234def5", "abc12345def4", "abc1234def45", "abc12345def456"),
            List.of("abc12def345", "abc123def45", "abc1234def5", "abc1234def45", "abc12345def4", "abc12345def456"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("file01_v2", "file02_v1", "file10_v10", "file02_v10", "file10_v2", "file1_v10"),
            List.of("file01_v2", "file1_v10", "file02_v1", "file02_v10", "file10_v2", "file10_v10"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("chapter-2.1.1", "chapter-10.1.1", "chapter-2.1.10", "chapter-10.1.2", "chapter-2.1.2"),
            List.of("chapter-2.1.1", "chapter-2.1.2", "chapter-2.1.10", "chapter-10.1.1", "chapter-10.1.2"),
            comparator
        );
        assertComparatorSortingMatches(
            List.of("item_1_2_3", "item_2_1_3", "item_1_10_3", "item_2_2_1", "item_1_2_10", "item_2_1_10", "item_1_10_1"),
            List.of("item_1_2_3", "item_1_2_10", "item_1_10_1", "item_1_10_3", "item_2_1_3", "item_2_1_10", "item_2_2_1"),
            comparator
        );
    }

    private void assertComparatorSortingMatches(
        @NotNull Collection<? extends CharSequence> input,
        @NotNull Collection<? extends CharSequence> expected,
        @NotNull Comparator<? super CharSequence> comparator
    ) {
        final ArrayList<? extends CharSequence> sorted = new ArrayList<>(input);
        sorted.sort(comparator);

        assertEquals(expected, sorted);
    }


}